﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SQLite;

namespace GDA.Provider.SQLite
{
    public class SQLiteProvider : Provider
    {
        #region Variables Estáticas

        /// <summary>
        /// Vetor que realiza a conversão do tipo do banco de dados para o tipo do sistema.
        /// </summary>
        private static Type[] _dbtypeToType = 
        {
          typeof(string),   // 0
          typeof(byte[]),   // 1
          typeof(byte),     // 2
          typeof(bool),     // 3
          typeof(decimal),  // 4
          typeof(DateTime), // 5
          typeof(DateTime), // 6
          typeof(decimal),  // 7
          typeof(double),   // 8
          typeof(Guid),     // 9
          typeof(Int16),
          typeof(Int32),
          typeof(Int64),
          typeof(object),
          typeof(sbyte),
          typeof(float),
          typeof(string),
          typeof(DateTime),
          typeof(UInt16),
          typeof(UInt32),
          typeof(UInt64),
          typeof(double),
          typeof(string),
          typeof(string),
          typeof(string),
          typeof(string),   // 25 (Xml)
        };

        /// <summary>
        /// Relação do tipos do banco de dados e seus nomes.
        /// </summary>
        private static SQLiteTypeNames[] _dbtypeNames = {
          new SQLiteTypeNames("INTEGER", DbType.Int64),
          new SQLiteTypeNames("TINYINT", DbType.Byte),
          new SQLiteTypeNames("INT", DbType.Int32),
          new SQLiteTypeNames("VARCHAR", DbType.AnsiString),
          new SQLiteTypeNames("NVARCHAR", DbType.String),
          new SQLiteTypeNames("CHAR", DbType.AnsiStringFixedLength),
          new SQLiteTypeNames("NCHAR", DbType.StringFixedLength),
          new SQLiteTypeNames("FLOAT", DbType.Double),
          new SQLiteTypeNames("REAL", DbType.Single),          
          new SQLiteTypeNames("BIT", DbType.Boolean),
          new SQLiteTypeNames("DECIMAL", DbType.Decimal),
          new SQLiteTypeNames("DATETIME", DbType.DateTime),
          new SQLiteTypeNames("BLOB", DbType.Binary),
          new SQLiteTypeNames("UNIQUEIDENTIFIER", DbType.Guid),
          new SQLiteTypeNames("SMALLINT", DbType.Int16),
        };

        private static SQLiteTypeNames[] _typeNames = {
          new SQLiteTypeNames("COUNTER", DbType.Int64),
          new SQLiteTypeNames("AUTOINCREMENT", DbType.Int64),
          new SQLiteTypeNames("IDENTITY", DbType.Int64),
          new SQLiteTypeNames("LONGTEXT", DbType.String),
          new SQLiteTypeNames("LONGCHAR", DbType.String),
          new SQLiteTypeNames("LONGVARCHAR", DbType.String),
          new SQLiteTypeNames("LONG", DbType.Int64),
          new SQLiteTypeNames("TINYINT", DbType.Byte),
          new SQLiteTypeNames("INTEGER", DbType.Int64),
          new SQLiteTypeNames("INT", DbType.Int32),
          new SQLiteTypeNames("VARCHAR", DbType.String),
          new SQLiteTypeNames("NVARCHAR", DbType.String),
          new SQLiteTypeNames("CHAR", DbType.String),
          new SQLiteTypeNames("NCHAR", DbType.String),
          new SQLiteTypeNames("TEXT", DbType.String),
          new SQLiteTypeNames("NTEXT", DbType.String),
          new SQLiteTypeNames("STRING", DbType.String),
          new SQLiteTypeNames("DOUBLE", DbType.Double),
          new SQLiteTypeNames("FLOAT", DbType.Double),
          new SQLiteTypeNames("REAL", DbType.Single),          
          new SQLiteTypeNames("BIT", DbType.Boolean),
          new SQLiteTypeNames("YESNO", DbType.Boolean),
          new SQLiteTypeNames("LOGICAL", DbType.Boolean),
          new SQLiteTypeNames("BOOL", DbType.Boolean),
          new SQLiteTypeNames("NUMERIC", DbType.Decimal),
          new SQLiteTypeNames("DECIMAL", DbType.Decimal),
          new SQLiteTypeNames("MONEY", DbType.Decimal),
          new SQLiteTypeNames("CURRENCY", DbType.Decimal),
          new SQLiteTypeNames("TIME", DbType.DateTime),
          new SQLiteTypeNames("DATE", DbType.DateTime),
          new SQLiteTypeNames("SMALLDATE", DbType.DateTime),
          new SQLiteTypeNames("BLOB", DbType.Binary),
          new SQLiteTypeNames("BINARY", DbType.Binary),
          new SQLiteTypeNames("VARBINARY", DbType.Binary),
          new SQLiteTypeNames("IMAGE", DbType.Binary),
          new SQLiteTypeNames("GENERAL", DbType.Binary),
          new SQLiteTypeNames("OLEOBJECT", DbType.Binary),
          new SQLiteTypeNames("GUID", DbType.Guid),
          new SQLiteTypeNames("UNIQUEIDENTIFIER", DbType.Guid),
          new SQLiteTypeNames("MEMO", DbType.String),
          new SQLiteTypeNames("NOTE", DbType.String),
          new SQLiteTypeNames("SMALLINT", DbType.Int16),
          new SQLiteTypeNames("BIGINT", DbType.Int64),
        };

        #endregion

        #region Estruturas Internas

        /// <summary>
        /// Armazena as informações que relação o nome do tipo do campo com o enum dos tipos de dados.
        /// </summary>
        internal struct SQLiteTypeNames
        {
            internal SQLiteTypeNames(string newtypeName, DbType newdataType)
            {
                typeName = newtypeName;
                dataType = newdataType;
            }

            internal string typeName;
            internal DbType dataType;
        }

        #endregion

        public SQLiteProvider()
            : base("SQLite", typeof(SQLiteConnection), typeof(SQLiteDataAdapter), typeof(SQLiteCommand), typeof(SQLiteParameter), "@")
        {
            
        }

        public override string SqlQueryReturnIdentity
        {
            get
            {
                return "Select last_insert_rowid()";
            }
        }

        public override string QuoteExpressionBegin
        {
            get
            {
                return "[";
            }
        }

        public override string QuoteExpressionEnd
        {
            get
            {
                return "]";
            }
        }

        public override string StatementTerminator
        {
            get
            {
                return ";";
            }
        }

        public override string QuoteExpression(string word)
        {
            return "[" + word + "]";
        }

        public override long GetDbType(string dbType, bool isUnsigned)
        {
            if (String.IsNullOrEmpty(dbType)) return (long)DbType.Object;

            int x = _typeNames.Length;
            for (int n = 0; n < x; n++)
            {
                if (String.Compare(dbType, 0, _typeNames[n].typeName, 0, _typeNames[n].typeName.Length, StringComparison.OrdinalIgnoreCase) == 0)
                    return (long)_typeNames[n].dataType;
            }
            return (long)DbType.Object;
        }

        public override Type GetSystemType(long dbType)
        {
            return _dbtypeToType[dbType];
        }

        public override long GetDbType(Type type)
        {
            for (int i = 0; i < _dbtypeToType.Length; i++)
                if (_dbtypeToType[i] == type)
                    return (long)i;

            return GDA.Provider.Provider.No_DbType;
        }
    }
}
